from flask import render_template, Blueprint, request, jsonify,current_app,make_response,flash,redirect,url_for
from applications.common.utils.http import success_api, fail_api
from applications.common.utils.rights import authorize
from applications.common.utils.validate import xss_escape
from applications.extensions import db
import html,json
from .models.admin_iptvadmin_channel import admin_iptvadmin_channel as Channel  # 从本地models导入Channel
from .schemas import admin_iptvadmin_channel_webOutSchema
from .models.admin_iptvadmin_channel import admin_iptvadmin_category as Category  # 从本地models导入Category
from .schemas import admin_iptvadmin_category_webOutSchema
from .models.admin_iptvadmin_channel import admin_iptvadmin_rss as Rss  # 从本地models导入Rss
from .schemas import admin_iptvadmin_rss_webOutSchema
from .models.admin_iptvadmin_channel import admin_iptvadmin_client as Client  # 从本地models导入Client
from .schemas import admin_iptvadmin_client_webOutSchema
from .models.admin_iptvadmin_channel import admin_iptvadmin_client_log as ClientLog  # 从本地models导入ClientLog
from .schemas import admin_iptvadmin_client_log_webOutSchema
from datetime import datetime, timedelta
from flask_login import current_user
import requests 
from urllib.parse import urlparse
import socket
import os
import time
from werkzeug.utils import secure_filename
import base64
import hashlib
# 添加自己的 xss_escape 函数
def xss_escape(s):
    """
    XSS防护
    """
    if s is None:
        return None
    return html.escape(str(s))


# 创建蓝图
iptvadmin_blueprint = Blueprint('iptvadmin', __name__, template_folder='templates', static_folder="static", url_prefix="/iptvadmin")



# 频道列表页面
@iptvadmin_blueprint.route("/")
@authorize("system:iptvadmin:main")
def main():
    
    try:
        # 初始化数据库
        inspector = db.inspect(db.engine)
        if 'admin_iptv_channel' not in inspector.get_table_names():
            Channel.__table__.create(db.engine)
            Category.__table__.create(db.engine)
            # 添加示例数据
            demo_channel = Channel(
                name="CCTV-1",
                category="默认分类",
                url="http://example.com/cctv1",
                create_time=datetime.now()
            )
            # 添加示例分类
            demo_category = Category(
                name="默认分类",
                sort=0,
                create_time=datetime.now()
            )
            db.session.add(demo_channel)
            db.session.add(demo_category)
            db.session.commit()

        # 刷新当前用户会话
        if current_user.is_authenticated:
            db.session.refresh(current_user)
        
        # 获取分类数据
        categories = Category.query.order_by(Category.sort.asc()).all()

        return render_template('index.html', categories=categories)
    except Exception as e:
        current_app.logger.error(f"Error in main route: {str(e)}")
        db.session.rollback()
        return render_template('index.html')
    finally:
        db.session.close()


# 新增频道页面
@iptvadmin_blueprint.get("/add")
@authorize("system:iptvadmin:add")
def add():
    # 获取分类数据
    categories = Category.query.order_by(Category.sort.asc()).all()
    return render_template('add.html', categories=categories)

# 编辑频道页面
@iptvadmin_blueprint.get("/edit")
@authorize("system:iptvadmin:edit")
def edit():
    channel_id = request.args.get('id')
    channel = Channel.query.filter_by(id=channel_id).first()
    # 获取分类数据
    categories = Category.query.order_by(Category.sort.asc()).all()
    return render_template('edit.html', channel=channel, categories=categories)

# 查询频道列表
@iptvadmin_blueprint.get("/query")
@authorize("system:iptvadmin:query")
def query():
    try:
        # 获取请求参数
        page = request.args.get('page', type=int, default=1)
        limit = request.args.get('limit', type=int, default=10)
        channel_name = request.args.get('channelName', '')
        category = request.args.get('category', '')
        
        # 查询构造
        query = Channel.query
        if channel_name:
            query = query.filter(Channel.name.like(f'%{xss_escape(channel_name)}%'))
        if category:
            query = query.filter(Channel.category == category)
            
        total = query.count()
        if page and limit:
            pagination = query.order_by(Channel.create_time.desc()) \
                            .paginate(page=page, per_page=limit, error_out=False)
            data = pagination.items
        else:
            data = query.order_by(Channel.create_time.desc()).all()
        # 构造响应数据
        content = [{
            'id': item.id,
            'name': item.name,
            'category': item.category,
            'url': item.url,
            'create_time': str(item.create_time)
        } for item in data]
        
        return {
            'code': 0,
            'msg': 'success',
            'count': total,
            'data': content
        }
    except Exception as e:
        # 记录错误日志
        current_app.logger.error(f"Query channels error: {str(e)}")
        return {
            'code': 1,
            'msg': '查询失败，请稍后重试',
            'count': 0,
            'data': []
        }
# 新增频道
@iptvadmin_blueprint.post("/save")
@authorize("system:iptvadmin:add")
def save():
    try:
        req_json = request.get_json(force=True)
        name = xss_escape(req_json.get('name'))
        category = req_json.get('category')
        url = xss_escape(req_json.get('url'))
        
        if not all([name, category, url]):
            return fail_api(msg="参数不完整")
            
        channel = Channel(
            name=name,
            category=category,
            url=url,
            create_time=datetime.now()
        )
        
        db.session.add(channel)
        db.session.commit()
        return success_api(msg="添加成功")
    except Exception as e:
        return fail_api(msg=f"添加失败: {str(e)}")

# 更新频道
@iptvadmin_blueprint.put("/update")
@authorize("system:iptvadmin:edit")
def update():
    try:
        req_json = request.get_json(force=True)
        channel_id = req_json.get('id')
        name = xss_escape(req_json.get('name'))
        category = req_json.get('category')
        url = xss_escape(req_json.get('url'))
        
        if not all([channel_id, name, category, url]):
            return fail_api(msg="参数不完整")
            
        channel = Channel.query.filter_by(id=channel_id).first()
        if not channel:
            return fail_api(msg="频道不存在")
            
        channel.name = name
        channel.category = category
        channel.url = url
        
        db.session.commit()
        return success_api(msg="更新成功")
    except Exception as e:
        return fail_api(msg=f"更新失败: {str(e)}")

# 删除频道
@iptvadmin_blueprint.post("/remove")
@authorize("system:iptvadmin:remove")
def remove():
    try:
        channel_id = request.form.get('id')
        channel = Channel.query.filter_by(id=channel_id).first()
        if not channel:
            return fail_api(msg="频道不存在")
            
        db.session.delete(channel)
        db.session.commit()
        return success_api(msg="删除成功")
    except Exception as e:
        return fail_api(msg=f"删除失败: {str(e)}")

# 批量删除频道
@iptvadmin_blueprint.post("/batchRemove")
@authorize("system:iptvadmin:remove")
def batch_remove():
    try:
        if request.form.get('all') == 'true':
            # 删除所有数据
            count = Channel.query.count()  # 获取删除前的数据总数
            Channel.query.delete()
            db.session.commit()
            return success_api(msg=f"成功删除全部{count}条数据")
        else:
            # 删除选中的数据
            ids = request.form.getlist('ids[]')
            if not ids:
                return fail_api(msg="请选择要删除的数据")
            
            count = Channel.query.filter(Channel.id.in_(ids)).count()
            Channel.query.filter(Channel.id.in_(ids)).delete(synchronize_session=False)
            db.session.commit()
            return success_api(msg=f"成功删除{count}条数据")
            
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"批量删除失败: {str(e)}")
        return fail_api(msg=f"删除失败: {str(e)}")
    

# 设置分类页面
@iptvadmin_blueprint.get("/setcategory")
@authorize("system:iptvadmin:setcategory")
def setcategory():
    try:
        # 初始化数据库
        inspector = db.inspect(db.engine)
        if 'admin_iptv_category' not in inspector.get_table_names():
            Category.__table__.create(db.engine)
            
            # 添加示例分类
            demo_category = Category(
                name="默认分类",
                sort=0,
                create_time=datetime.now()
            )
            db.session.add(demo_category)
            db.session.commit()

        # 刷新当前用户会话
        if current_user.is_authenticated:
            db.session.refresh(current_user)
        
        return render_template('category.html')
    except Exception as e:
        current_app.logger.error(f"Error in main route: {str(e)}")
        db.session.rollback()
    return render_template('category.html')

# 新增分类页面
@iptvadmin_blueprint.get("/category/add")
@authorize("system:iptvadmin:category")
def category_add():
    return render_template('category_add.html')

# 编辑分类页面
@iptvadmin_blueprint.get("/category/edit")
@authorize("system:iptvadmin:category")
def category_edit():
    category_id = request.args.get('id')
    category = Category.query.filter_by(id=category_id).first()
    return render_template('category_edit.html', category=category)


# 查询分类列表
@iptvadmin_blueprint.get("/category/query")
@authorize("system:iptvadmin:category")
def category_query():
    try:
        page = request.args.get('page', type=int)
        limit = request.args.get('limit', type=int)
        
        query = Category.query
        total = query.count()
        
        if page and limit:
            categories = query.order_by(Category.sort.asc())\
                            .paginate(page=page, per_page=limit)
            data = categories.items
        else:
            data = query.order_by(Category.sort.asc()).all()
            
        return {
            'code': 0,
            'msg': 'success',
            'count': total,
            'data': admin_iptvadmin_category_webOutSchema(many=True).dump(data)
        }
    except Exception as e:
        return {'code': 1, 'msg': str(e), 'count': 0, 'data': []}

# 新增分类
@iptvadmin_blueprint.post("/category/save")
@authorize("system:iptvadmin:category")
def category_save():
    try:
        data = request.get_json()
        name = xss_escape(data.get('name'))
        
        # 检查分类名称是否已存在
        if Category.query.filter_by(name=name).first():
            return fail_api(msg="分类名称已存在")
            
        category = Category(
            name=name,
            sort=data.get('sort', 0)
        )
        db.session.add(category)
        db.session.commit()
        return success_api(msg="添加成功")
    except Exception as e:
        db.session.rollback()
        return fail_api(msg=str(e))

# 更新分类-编辑
@iptvadmin_blueprint.put("/category/update")
@authorize("system:iptvadmin:category")
def category_update():
    try:
        data = request.get_json()
        category_id = data.get('id')
        name = xss_escape(data.get('name'))
        
        # 检查分类名称是否已存在(排除当前记录)
        if name and Category.query.filter(
            Category.name == name,
            Category.id != category_id
        ).first():
            return fail_api(msg="分类名称已存在")
            
        category = Category.query.get_or_404(category_id)
        if name:
            category.name = name
        if 'sort' in data:
            category.sort = data.get('sort')
            
        db.session.commit()
        return success_api(msg="更新成功")
    except Exception as e:
        db.session.rollback()
        return fail_api(msg=str(e))

# 删除分类
@iptvadmin_blueprint.post("/category/remove")
@authorize("system:iptvadmin:category")
def category_remove():
    try:
        category_id = request.form.get('id')
        category = Category.query.get_or_404(category_id)
        db.session.delete(category)
        db.session.commit()
        return success_api(msg="删除成功")
    except Exception as e:
        return fail_api(msg=str(e))
    
 # 批量删除分类
@iptvadmin_blueprint.post("/category/batchRemove")
@authorize("system:iptvadmin:category")
def category_batch_remove():
    """批量删除分类"""
    try:
        # 检查是否有关联数据
        # def check_related_data(category_ids):
        #     # 这里添加检查关联数据的逻辑
        #     # 例如：检查是否有频道使用这些分类
        #     related = Channel.query.filter(Channel.category_id.in_(category_ids)).first()
        #     if related:
        #         return True
        #     return False

        if request.form.get('all') == 'true':
            # 删除所有数据前检查
            all_ids = [c.id for c in Category.query.all()]
            if not all_ids:
                return fail_api(msg="没有可删除的数据")
                
            # if check_related_data(all_ids):
            #     return fail_api(msg="存在关联的频道数据，无法删除")
                
            count = Category.query.count()
            Category.query.delete()
            db.session.commit()
            current_app.logger.info(f"已删除所有分类数据，共{count}条")
            return success_api(msg=f"已删除全部数据，共{count}条")
        else:
            # 获取选中的ID列表
            ids = request.form.get('ids', '').split(',')
            if not ids or ids[0] == '':
                return fail_api(msg="未选择要删除的数据")
            
            try:
                ids = [int(id_) for id_ in ids]
            except ValueError:
                return fail_api(msg="无效的ID格式")
                
            # 检查关联数据
            # if check_related_data(ids):
            #     return fail_api(msg="选中的分类中存在关联的频道数据，无法删除")
                
            # 删除指定ID的数据
            result = Category.query.filter(Category.id.in_(ids)).delete(synchronize_session=False)
            if not result:
                return fail_api(msg="未找到要删除的数据")
                
            db.session.commit()
            current_app.logger.info(f"批量删除分类成功，ID: {ids}")
            return success_api(msg=f"成功删除 {result} 条数据")
            
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"批量删除失败: {str(e)}")
        return fail_api(msg="操作失败，请稍后重试")

# 批量导入页面
@iptvadmin_blueprint.get("/iptvimport")
@authorize("system:iptvadmin:iptvimport")
def iptvimport():
    return render_template('iptvimport.html')

# 下载模板
@iptvadmin_blueprint.get("/import/template")
@authorize("system:iptvadmin:iptvimport")
def download_template():
    template_content = "频道名称,分类,播放地址\nCCTV-1,央视频道,http://example.com/cctv1"
    # 返回模板内容
    return jsonify({'code': 0, 'msg': 'success', 'data': template_content})

# 上传并导入
@iptvadmin_blueprint.post("/import/upload")
@authorize("system:iptvadmin:iptvimport")
def upload_import():
    try:
        if 'file' not in request.files:
            return fail_api(msg='未找到上传文件')
            
        file = request.files['file']
        if not file.filename.endswith('.txt'):
            return fail_api(msg='仅支持txt格式文件')

        start_time = time.time()
        total = success = 0
        fail_details = []
        
        
        # 读取并处理文件内容
        content = file.read().decode('utf-8')
        lines = content.splitlines()
        
        for line_num, line in enumerate(lines, 1):
            try:
                if not line.strip():
                    continue
                    
                # 解析数据:txt文件格式:频道名称,播放地址,分类
                parts = line.strip().split(',')
                if len(parts) not in [2, 3]:  # 支持2列或3列数据
                    fail_details.append({
                        'line': line_num,
                        'reason': '数据格式错误,请使用英文逗号,分隔的2列或3列数据'
                    })
                    continue # 跳过当前行
                
                if len(parts) == 2:
                    name, url = parts
                    category_name = '默认分类'  # 如果只有2列，使用默认分类
                else:
                    name, url, category_name = parts

                # 获取或创建分类
                category = Category.query.filter_by(name=category_name).first()
                if not category:
                    # 如果分类不存在，则报错
                    fail_details.append({
                        'line': line_num,
                        'reason': '分类不存在,请先创建分类'
                    })
                    continue # 跳过当前行

                # 检查频道、分类、播放地址同时存在,则不导入
                if Channel.query.filter_by(name=name,category=category_name,url=url).first():
                    fail_details.append({
                        'line': line_num,
                        'reason': '频道、播放地址、分类同时存在'
                    })
                    continue # 跳过当前行
                # 创建频道
                channel = Channel(
                    name=name,
                    category=category_name,
                    url=url,
                    create_time=datetime.now()
                )
                db.session.add(channel)
                success += 1
                
            except Exception as e:
                fail_details.append({
                    'line': line_num,
                    'reason': str(e)
                })
                
            total += 1
            
        db.session.commit()
        
        #  修改返回格式
        if len(fail_details) > 0:
            return {
                'success': False,
                'msg': f'导入完成，但存在{len(fail_details)}条错误数据',
                'data': {
                    'total': total,
                    'success': success,
                    'fail': len(fail_details),
                    'time': round(time.time() - start_time, 2),
                    'failDetails': fail_details
                }
            }
        else:
            return {
                'success': True,
                'msg': '导入成功',
                'data': {
                    'total': total,
                    'success': success,
                    'fail': 0,
                    'time': round(time.time() - start_time, 2),
                    'failDetails': []
                }
            }
        
    except Exception as e:
        db.session.rollback()
        return fail_api(msg=str(e))
    

# rss订阅页面
@iptvadmin_blueprint.get("/rss")
@authorize("system:iptvadmin:rss")
def rss():
    # 初始化数据库
    inspector = db.inspect(db.engine)
    if 'admin_iptv_rss' not in inspector.get_table_names():
        Rss.__table__.create(db.engine)
        # 添加示例数据
        demo_rss = Rss(
            name="默认订阅",
            type="m3u",
            url="http://example.com/default",
            category="默认分类",
            status=True,
            sort=0,
            encrypt=False,
            enable=True,
            create_time=datetime.now()
        )
        current_app.logger.info(f"demo_rss: {demo_rss}")
        db.session.add(demo_rss)
        db.session.commit()

    # 刷新当前用户会话
    if current_user.is_authenticated:
        db.session.refresh(current_user)
    rss = Rss.query.all()
    return render_template('rss.html')

@iptvadmin_blueprint.get("/rss/add")
@authorize("system:iptvadmin:rss")
def rss_add():
    """添加订阅页面"""
    return render_template('rss_add.html')

@iptvadmin_blueprint.get("/rss/edit")   
@authorize("system:iptvadmin:rss")
def rss_edit():
    """编辑订阅页面"""
    rss_id = request.args.get('id')
    rss_data = Rss.query.filter_by(id=rss_id).first()
 
    return render_template('rss_edit.html', rss=rss_data)

@iptvadmin_blueprint.get("/rss/data")
@authorize("system:iptvadmin:rss")
def rss_data():
    """获取订阅列表数据"""
    page = request.args.get('page', 1, type=int)
    limit = request.args.get('limit', 10, type=int)
    name = request.args.get('name', '')
    type = request.args.get('type', '')

    # 初始化查询对象
    query = Rss.query

    # 根据条件添加过滤
    if name:
        query = query.filter(Rss.name.like(f'%{name}%'))
    if type:
        query = query.filter(Rss.type == type)

    total = query.count()
    rss_list = query.order_by(Rss.id.desc()).paginate(page=page, per_page=limit)
    
    return jsonify({
        'code': 0,
        'msg': '',
        'count': total,
        'data': [sub.to_dict() for sub in rss_list.items]
    })



# 新增外部订阅，保存
@iptvadmin_blueprint.post("/rss/save")
@authorize("system:iptvadmin:rss")
def rss_save():
    """保存新订阅"""
    try:
        data = request.get_json()
        
        # 检查必要参数
        name = data.get('name', '').strip()
        if not name:
            return jsonify({'success': False, 'msg': '订阅名称不能为空'})
            
        # 检查名称是否已存在（不使用数据库约束，只用查询判断）
        if Rss.query.filter(Rss.name == name).first():
            return jsonify({'success': False, 'msg': f'订阅名称 "{name}" 已存在'})
        
        # 获取和检查URL
        url = data.get('url', '').strip()
        if not url:
            return jsonify({'success': False, 'msg': '订阅地址不能为空'})
            
        # 处理enable值
        enable_value = data.get('enable', '0')
        enable = bool(int(enable_value)) if isinstance(enable_value, str) else bool(enable_value)
        
        # 处理encrypt值
        encrypt_value = data.get('encrypt', '0')
        encrypt = bool(int(encrypt_value)) if isinstance(encrypt_value, str) else bool(encrypt_value)
        
        # 处理加密URL
        if encrypt and '&androidid={androidid}' not in url:
            url = url.replace('&androidid={androidid}', '')
            url = url + '&androidid={androidid}'
        elif not encrypt and '&androidid={androidid}' in url:
            url = url.replace('&androidid={androidid}', '')
            url = url + '&androidid={androidid}'
            
        subscription = Rss(
            name=name,
            type=data.get('type'),
            url=url,
            category='外部订阅',
            status=True,
            encrypt=encrypt,
            sort=data.get('sort', 0),
            enable=enable,
            remark=data.get('remark'),
            create_time=datetime.now()
        )
        
        db.session.add(subscription)
        db.session.commit()
        # 保存客户端配置
        client_config_save(name,url)  # 保存客户端配置
        return jsonify({'success': True, 'msg': '添加成功'})
            
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"添加订阅失败: {str(e)}")
        return jsonify({'success': False, 'msg': f'添加失败：{str(e)}'})
    
# 更新订阅
@iptvadmin_blueprint.post("/rss/update")
@authorize("system:iptvadmin:rss")
def rss_update():
    """更新订阅"""
    try:
        data = request.get_json()
        if not data or 'id' not in data:
            return jsonify({'success': False, 'msg': '缺少必要的参数'})
            
        subscription = Rss.query.get(data.get('id'))
        if not subscription:
            return jsonify({'success': False, 'msg': '未找到要更新的订阅'})
        
        # 检查名称
        name = data.get('name', '').strip()
        if not name:
            return jsonify({'success': False, 'msg': '订阅名称不能为空'})
            
        # 检查名称是否与其他订阅重复（排除自身）
        existing_subscription = Rss.query.filter(
            Rss.name == name,
            Rss.id != subscription.id
        ).first()
        if existing_subscription:
            return jsonify({'success': False, 'msg': f'订阅名称 "{name}" 已存在'})
        
        # 获取原始URL
        url = data.get('url', '').strip()
        if not url:
            return jsonify({'success': False, 'msg': '订阅地址不能为空'})
            
        # 处理enable值
        enable_value = data.get('enable', '0')
        enable = bool(int(enable_value)) if isinstance(enable_value, str) else bool(enable_value)
        
        # 处理encrypt值
        encrypt_value = data.get('encrypt', '0')
        encrypt = bool(int(encrypt_value)) if isinstance(encrypt_value, str) else bool(encrypt_value)
        
        # 处理加密URL
        if encrypt and '&androidid={androidid}' not in url:
            url = url.replace('&androidid={androidid}', '')
            url = url + '&androidid={androidid}'
        elif not encrypt and '&androidid={androidid}' in url:
            url = url.replace('&androidid={androidid}', '')
            url = url + '&androidid={androidid}'
        
        # 更新字段
        subscription.name = name
        subscription.type = data.get('type')
        subscription.url = url
        subscription.sort = data.get('sort', 0)
        subscription.enable = enable
        subscription.encrypt = encrypt
        subscription.remark = data.get('remark')
        subscription.update_time = datetime.now()
        
        # 直接提交更新
        db.session.commit()
        # 保存客户端配置
        client_config_save(name,url)  # 保存客户端配置
        return jsonify({'success': True, 'msg': '更新成功'})
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"更新订阅失败: {str(e)}")  # 添加错误日志
        return jsonify({'success': False, 'msg': f'更新失败：{str(e)}'})

@iptvadmin_blueprint.post("/rss/remove")
@authorize("system:iptvadmin:remove")
def rss_remove():
    """删除订阅"""
    subscription_id = request.form.get('id', type=int)
    subscription = Rss.query.get_or_404(subscription_id)
    
    try:
        db.session.delete(subscription)
        db.session.commit()
        # 删除客户端配置
        delete_client_config(subscription.name)
        return jsonify({'success': True, 'msg': '删除成功'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'msg': f'删除失败：{str(e)}'})

@iptvadmin_blueprint.post("/rss/batchRemove")
@authorize("system:iptvadmin:remove")
def rss_batch_remove():
    """批量删除订阅"""
    try:
        if request.form.get('all') == 'true':
            # 删除所有数据
            Rss.query.delete()
            db.session.commit()
            # 删除客户端配置
            # 获取当前文件所在目录
            current_dir = os.path.dirname(os.path.abspath(__file__))
            # 构建配置文件路径
            config_path = current_dir + f'/templates/client/config/'
            # 删除config_path目录下除default.json外的所有文件
            for file in os.listdir(config_path):
                if file != 'default.json':
                    os.remove(os.path.join(config_path, file))

            return jsonify({'success': True, 'msg': '所有数据删除成功'})
        else:
            # 获取选中的ID列表
            ids = request.form.get('ids', '').split(',')
            if not ids or ids[0] == '':
                return jsonify({'success': False, 'msg': '未选择要删除的数据'})
            
            # 批量删除客户端配置
            for id in ids:
                delete_client_config(Rss.query.get(id).name)
            # 删除指定ID的数据
            Rss.query.filter(Rss.id.in_(ids)).delete(synchronize_session=False)
            db.session.commit()
            
            
            return jsonify({'success': True, 'msg': '批量删除成功'})
            
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"批量删除失败: {str(e)}")
        return jsonify({'success': False, 'msg': f'批量删除失败：{str(e)}'})

# 订阅状态切换
@iptvadmin_blueprint.post("/rss/enable")
@authorize("system:iptvadmin:rss")
def rss_toggle_enable():
    """切换订阅状态"""
    subscription_id = request.form.get('id', type=int)
    enable = request.form.get('enable', type=int)
    
    subscription = Rss.query.get_or_404(subscription_id)
    try:
        subscription.enable = bool(enable)
        Rss.query.filter_by(id=subscription_id).update({'enable': subscription.enable})
        db.session.commit()
        db.session.close()
        return jsonify({'success': True, 'msg': '状态更新成功'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'msg': f'状态更新失败：{str(e)}'})

#    订阅加密状态切换
@iptvadmin_blueprint.post("/rss/encrypt")
@authorize("system:iptvadmin:rss")
def rss_toggle_encrypt():
    """切换订阅加密状态"""
    subscription_id = request.form.get('id', type=int)
    encrypt = request.form.get('encrypt', type=int)
    subscription = Rss.query.get_or_404(subscription_id)
    url = subscription.url
    try:
        # 根据加密状态，更新订阅地址
        if encrypt:
            url = url.replace('&androidid={androidid}', '')
            url = url + '&androidid={androidid}' 
            subscription.encrypt = True
        else:
            url = url.replace('&androidid={androidid}', '') # 如果取消加密，则删除androidid和aes
            url = url + '&androidid={androidid}'
            subscription.encrypt = False
              
        # subscription.encrypt = bool(encrypt)
        # 更新订阅地址
        Rss.query.filter_by(id=subscription_id).update({'url': url, 'encrypt': encrypt})
        
        # 保存客户端配置
        client_config_save(subscription.name,url)  # 保存客户端配置
        db.session.commit()
        db.session.close()
        return jsonify({'success': True, 'msg': '状态更新成功'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'msg': f'状态更新失败：{str(e)}'})

# 订阅只需检查订阅的url是否能访问
@iptvadmin_blueprint.post("/rss/check")
@authorize("system:iptvadmin:rss")
def rss_check():
    """检查订阅地址是否可访问"""
    try:
        # 支持两种请求方式：JSON 和 Form
        if request.is_json:
            data = request.get_json()
        else:
            data = request.form

        if not data:
            return jsonify({'success': False, 'msg': '请提供订阅地址'})
            
        url = data.get('url', '').strip()
        if not url:
            return jsonify({'success': False, 'msg': '订阅地址不能为空'})

        # 处理不完整的URL
        if not url.startswith(('http://', 'https://')):
            url = f'http://{url}'

        # 设置请求头
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            'Accept': '*/*',
            'Accept-Encoding': 'gzip, deflate',
            'Connection': 'keep-alive'
        }

        try:
            # 发送请求
            response = requests.get(
                url,
                headers=headers,
                timeout=10,
                verify=False,  # 不验证SSL证书
                allow_redirects=True
            )
        except requests.exceptions.Timeout:
            return jsonify({'success': False, 'msg': '连接超时，请检查地址是否正确'})
        except requests.exceptions.SSLError:
            return jsonify({'success': False, 'msg': 'SSL证书验证失败'})
        except requests.exceptions.ConnectionError:
            return jsonify({'success': False, 'msg': '连接失败，请检查网络或地址是否正确'})
        except Exception as e:
            return jsonify({'success': False, 'msg': f'请求失败：{str(e)}'})

        # 检查响应
        if response.status_code == 200:
            content_type = response.headers.get('content-type', '').lower()
            try:
                content = response.text.lower()[:100]  # 只检查前100个字符
            except:
                content = ''

            # 检查内容类型和格式
            valid_content_types = [
                'text/plain', 'text/html', 'application/json',
                'application/xml', 'application/octet-stream'
            ]
            valid_formats = [
                '#extm3u', '#genre#', '[', '<?xml'
            ]

            # 检查内容是否有效
            content_valid = any(fmt in content_type for fmt in valid_content_types)
            format_valid = any(fmt in content for fmt in valid_formats)

            if content_valid or format_valid:
                return jsonify({
                    'success': True, 
                    'msg': '订阅地址可访问',
                    'data': {
                        'url': url,
                        'content_type': content_type,
                        'size': len(response.content)
                    }
                })
            else:
                return jsonify({
                    'success': False, 
                    'msg': '订阅内容格式不正确'
                })
        else:
            return jsonify({
                'success': False, 
                'msg': f'访问失败，状态码：{response.status_code}'
            })

    except Exception as e:
        current_app.logger.error(f"检查订阅地址失败: {url if 'url' in locals() else 'Unknown URL'}, 错误: {str(e)}")
        return jsonify({
            'success': False, 
            'msg': f'检查失败：{str(e)}'
        })

# 自定义订阅页面
@iptvadmin_blueprint.get("/rss/rss_custom/add")
@authorize("system:iptvadmin:rss")
def custom_rss():
    """自定义订阅页面"""
    categories = Category.query.order_by(Category.sort.asc()).all()
    return render_template('rss_custom_add.html', categories=categories)


from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import base64

@iptvadmin_blueprint.route('/api/rss/cust',methods=['GET','POST'])
def custom_data_rss():
    try:
        # 获取参数
        androidId = request.args.get('androidid')
        name = request.args.get('name')  # 订阅名称
        rss_type = request.args.get('type', 'json')  # 订阅类型
        categories = request.args.get('categories', '').split(',') if request.args.get('categories') else []  # 订阅分类

        # 验证客户端
        client, error = validate_client(androidId)
        if error:
            return jsonify(error), error['code']

        # 验证订阅信息
        rss, error = validate_subscription(name, rss_type, categories)
        if error:
            return jsonify(error), error['code']

        # 获取频道信息
        try:
            channels = Channel.query.filter(Channel.category.in_(categories)).all()
            channels = sorted(channels, key=lambda x: categories.index(x.category))
        except Exception as e:
            return jsonify({'code': 500, 'error': f'获取频道信息失败: {str(e)}'}), 500

        # 生成内容
        content, error = generate_content(rss_type, channels)
        if error:
            return jsonify(error), error['code']

        # 处理加密
        if rss.encrypt:
            try:
                content = aes_encrypt(
                    content,
                    client.androidId,
                    client.apkAppName,
                    client.apkPackageName
                )
                # return jsonify({'code': 200, 'data': content})
                return content
            except Exception as e:
                return jsonify({'code': 500, 'error': f'内容加密失败: {str(e)}'}), 500
        else:
            # return jsonify({'code': 200, 'data': content})
            return content
            # 处理文件下载
            response = make_response(content)
            filename = f"channels_{datetime.now().strftime('%Y%m%d')}"
            
            # 根据不同类型设置不同的文件扩展名和Content-Type
            content_types = {
                'm3u': ('m3u', 'application/vnd.apple.mpegurl'),
                'txt': ('txt', 'text/plain'),
                'json': ('json', 'application/json'),
                'genre': ('xml', 'application/xml')
            }
            
            ext, content_type = content_types.get(rss_type, ('txt', 'text/plain'))
            response.headers['Content-Disposition'] = f'attachment; filename="{filename}.{ext}"'
            response.headers['Content-Type'] = content_type
            return response

    except Exception as e:
        return jsonify({'code': 500, 'error': f'服务器内部错误: {str(e)}'}), 500

def validate_client(androidId):
    """验证客户端"""
    # if not androidId:
    #     return None, {'code': 400, 'error': '安卓ID不能为空'}
    
    client = Client.query.filter_by(androidId=androidId).first()
    if not client:
        return None, {'code': 400, 'error': '客户端未注册,请检查'}
    
    if not client.authorize:
        return None, {'code': 400, 'error': '客户端未授权,请检查'}
    
    return client, None

def validate_subscription(name, rss_type, categories):
    """验证订阅信息"""
    # 验证分类
    for category in categories:
        if not Category.query.filter_by(name=category).first():
            return None, {'code': 400, 'error': f'订阅信息分类:"{category}"错误,请检查'}
    
    # 验证订阅
    rss = Rss.query.filter_by(name=name, type=rss_type).first()
    if not rss:
        return None, {'code': 400, 'error': '订阅失效或者不存在,请检查'}
    
    if not rss.enable:
        return None, {'code': 400, 'error': '订阅已禁用,请联系管理员'}
    
    return rss, None

def generate_content(rss_type, channels):
    """生成不同格式的内容"""
    content_generators = {
        'm3u': generate_m3u_content,
        'txt': generate_txt_content,
        'json': generate_json_content,
        'genre': generate_genre_content
    }
    
    generator = content_generators.get(rss_type)
    if not generator:
        return None, {'code': 400, 'error': f'类型:{rss_type}不支持'}
    
    try:
        return generator(channels), None
    except Exception as e:
        return None, {'code': 500, 'error': f'生成内容失败: {str(e)}'}
    
# 自定义订阅数据-处理请求 外部可访问
# @iptvadmin_blueprint.route('/api/rss/cust',methods=['GET','POST'])
# def custom_data_rss():
#     # 如果订阅地址中存在androidid,则进行验证（可选）
#     # 待修改，此处需验证客户端是否授权
#     # 需要从客户端获取
#     # 1.安卓ID
#     # 2.APP名称
#     # 3.APP包名
#     # 4.APP版本
#     # 5.签名
#     # 进行AES加密，分发数据
#     try:
#         androidId=request.args.get('androidid')
#         name = request.args.get('name') # 订阅名称
#         rss_type = request.args.get('type', 'json') # 订阅类型
#         categories = request.args.get('categories', '').split(',') # 订阅分类
#         if androidId:
#             # 获取客户端信息
#             client = Client.query.filter_by(androidId=androidId).first()

#             if not client: 
#                 return jsonify({'code': 400, 'error': f'客户端未授权,请检查'}), 400
#             else:
#                 # 判断权限
#                 if not client.authorize:
#                     # 如果未授权，则返回错误信息
#                     return jsonify({'code': 400, 'error': f'客户端未授权,请检查'}), 400
#                 else:
#                     # 分析订阅地址信息
#                     # 检查分类名称是否存在，不存在则返回错误
#                     for category in categories:
#                         if not Category.query.filter_by(name=category).first():
#                             # app返回显示的错误信息，不易过长
#                             return jsonify({'code': 400, 'error': f'订阅信息分类:“{category}”错误,请检查'}), 400
#                     # 校验订阅地址是否启用
#                     rss = Rss.query.filter_by(name=name,type=rss_type).first()
#                     if not rss:
#                         # return jsonify({'code': 400, 'error': f'订阅:{host},不存在'}), 400
#                         return jsonify({'code': 400, 'error': f'订阅失效或者不存在,请检查'}), 400
#                     # 校验订阅地址是否启用
#                     if not rss.enable:
#                         # return jsonify({'code': 400, 'error': f'订阅地址:{host},未启用'}), 400
#                         return jsonify({'code': 400, 'error': f'订阅已禁用,请联系管理员'}), 400
                    
#                     try:
#                         # 按分类查询符合条件的频道
#                         channels = Channel.query.filter(Channel.category.in_(categories)).all()
#                         # 按分类排序，分类名称在categories列表中的顺序
#                         channels = sorted(channels, key=lambda x: categories.index(x.category))
#                         # 根据rss_type生成不同的内容
#                         if rss_type == 'm3u':
#                             content = generate_m3u_content(channels)
#                         elif rss_type == 'txt':
#                             content = generate_txt_content(channels)
#                         elif rss_type == 'json':
#                             content = generate_json_content(channels)
#                         elif rss_type == 'genre':
#                             content = generate_genre_content(channels)
#                         else:
#                             return jsonify({'code': 400, 'error': f'类型:{rss_type},不支持'}), 400

#                         # 校验订阅地址是否加密
#                         if rss.encrypt:
#                             # 获取客户端信息    
#                             client = Client.query.filter_by(androidId=androidId).first()
#                             # 加密 aes_encrypt(data, sig="12315", appname="mytv", packagename="com.mytv", method="AES-128-ECB"
#                             content = aes_encrypt(content,client.androidId,client.apkAppName,client.apkPackageName) # 加密,默认key
#                         else: # 不加密
#                             # 访问地址弹出下载
#                             response = make_response(content)
#                             response.headers['Content-Disposition'] = f'attachment; filename="channels{datetime.now().strftime("%Y%m%d")}.m3u"'
#                             response.headers['Content-Type'] = 'application/vnd.apple.mpegurl'
#                         return content
#                     except Exception as e:
#                         # 返回错误信息
#                         return jsonify({'code': 500, 'error': str(e)}), 500
        
#         else:
#             #
#             return jsonify({'code': 400, 'error': f'安卓ID不能为空'}), 400
    
#     except Exception as e:
#         return jsonify({'code': 500, 'error': str(e)}), 500
    
    

def generate_m3u_content(channels):
    """生成M3U格式的内容"""
    content = '#EXTM3U\n'
    for channel in channels:
        content += f'#EXTINF:-1 tvg-id="{channel.id}" tvg-name="{channel.name}",{channel.name}\n'
        content += f'{channel.url}\n'
    # 访问地址弹出下载
    # response = make_response(content)
    # response.headers['Content-Disposition'] = f'attachment; filename="channels{datetime.now().strftime("%Y%m%d")}.m3u"'
    # response.headers['Content-Type'] = 'application/vnd.apple.mpegurl'
    return content

def generate_txt_content(channels):
    """生成TXT格式的内容"""
    """
    频道名称,频道地址
    """
    content = ''
    # txt格式，每行一个频道，频道名称和频道地址用英文逗号分隔
    for channel in channels:
        content += f'{channel.name},{channel.url}\r\n'
    # 访问地址弹出下载
    # response = make_response(content)
    # response.headers['Content-Disposition'] = f'attachment; filename="channels{datetime.now().strftime("%Y%m%d")}.txt"'
    # response.headers['Content-Type'] = 'text/plain'
    return content

def generate_json_content(channels):
    """生成JSON格式的内容"""
    # 将频道对象转换为字典列表
    channel_list = [{
        'id': channel.id,
        'name': channel.name,
        'category': channel.category,
        'url': channel.url,
        'create_time': channel.create_time.strftime('%Y-%m-%d %H:%M:%S')
    } for channel in channels]
    return jsonify({'channels': channel_list})

def generate_genre_content(channels):
    """生成#GENRE#格式的内容
    
    Args:
        channels: 频道列表数据
        
    Returns:
        Response: 包含生成的内容的响应对象
        
    格式说明:
    分类名称1,#genre#
    频道名称,频道地址
    分类名称2,#genre#
    频道名称,频道地址
    """
    try:
        # 按分类分组
        category_dict = {}
        for channel in channels:
            if channel.category not in category_dict:
                category_dict[channel.category] = []
            category_dict[channel.category].append(channel)

        # 生成内容
        content_lines = []
        for category, channel_list in category_dict.items():
            # 添加分类标记
            content_lines.append(f'{category},#genre#')
            # 添加该分类下的所有频道
            for channel in channel_list:
                if channel.name and channel.url:  # 确保名称和地址不为空
                    content_lines.append(f'{channel.name},{channel.url}')
            # 添加空行分隔不同分类
            content_lines.append('')

        # 合并所有行，确保最后一行也有换行符
        content = '\n'.join(content_lines).rstrip() + '\n'

        # 生成文件名
        # filename = f"channels_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
        
        # 创建响应
        # response = make_response(content)
        # response.headers['Content-Disposition'] = f'attachment; filename="{filename}"'
        # response.headers['Content-Type'] = 'text/plain; charset=utf-8'
        # 确保内容是UTF-8编码的字符串
        if isinstance(content, bytes):
            content = content.decode('utf-8')
        return content
        
    except Exception as e:
        current_app.logger.error(f"生成GENRE内容失败: {str(e)}")
        return jsonify({'code': 500, 'error': str(e)}), 500
# 编辑页面
@iptvadmin_blueprint.get("/rss/rss_custom/edit")
@authorize("system:iptvadmin:rss")
def edit_custom_rss():
    from urllib.parse import urlparse, parse_qs
    from urllib.parse import unquote
    """编辑自定义订阅页面"""
    rss_id = request.args.get('id')
    rss = Rss.query.filter_by(id=rss_id).first()
    categories = Category.query.order_by(Category.sort.asc()).all()
    # 通过rssid查询url  
    url = Rss.query.filter_by(id=rss_id).first().url
    # 如果url存在，则获取url中的categories参数
    # 检查如果url中存在中文的编码，则转为中文
    if '%' in url:
        url = unquote(url)
    categories_2 = []
    if url:
        categories_2 = url.split('&categories=')
        if ',' in categories_2[1]:
            categories_2 = categories_2[1].split(',')
        else:
            categories_2 = categories_2[1].split('%2C')
    else:
        categories_2 = []
    return render_template('rss_custom_edit.html', rss=rss, categories=categories, categories_2=categories_2)

# 保存自定义订阅
@iptvadmin_blueprint.route('/rss/rss_custom/save', methods=['POST'])
@authorize("system:iptvadmin:rss")
def save_custom_rss():
    """保存自定义订阅"""
    try:
        data = request.get_json()
        # 检查订阅名称和类型是否一致
        if Rss.query.filter_by(name=data.get('name')).first():
            return jsonify({
            'success': False,
            'msg': f'订阅名称已存在'
        })

        enable_value = data.get('enable', '0')
        enable = bool(int(enable_value)) if isinstance(enable_value, str) else bool(enable_value)

        # 根据加密状态，更新订阅地址
        # 处理encrypt值
        encrypt_value = data.get('encrypt', '0')
        encrypt = bool(int(encrypt_value)) if isinstance(encrypt_value, str) else bool(encrypt_value)
        
        url = data.get('url', '').strip() # 获取订阅地址
        # 处理加密URL
        if encrypt and '&androidid={androidid}' not in url:
            url = url.replace('&androidid={androidid}', '')
            url = url + '&androidid={androidid}'
        elif not encrypt and '&androidid={androidid}' in url:
            url = url.replace('&androidid={androidid}', '')
            url = url + '&androidid={androidid}'

        # 创建新的RSS记录
        rss = Rss(
            name=data.get('name'),
            type=data.get('type'),
            url=url,
            category='自定义订阅',
            sort=data.get('sort', 0),
            encrypt=encrypt,
            enable=enable,
            remark=data.get('remark'),
            # is_custom=True  # 标记为自定义订阅
        )
        
        db.session.add(rss)
        db.session.commit()
        
        # 保存客户端配置
        client_config_save(rssname=data.get('name'),rssurl=url)

        db.session.refresh(rss)
        db.session.close()
        return jsonify({
            'success': True,
            'msg': '保存成功'
        })
    except Exception as e:
        db.session.rollback()
        return jsonify({
            'success': False,
            'msg': f'保存失败：{str(e)}'
        })
# 更新自定义订阅
@iptvadmin_blueprint.post("/rss/rss_custom/update")
@authorize("system:iptvadmin:rss")
def rss_custom_update():
    """更新自定义订阅"""
    try:
        data = request.get_json()
        if not data or 'id' not in data:
            return jsonify({'success': False, 'msg': '缺少必要的参数'})
            
        subscription = Rss.query.get(data.get('id'))
        if not subscription:
            return jsonify({'success': False, 'msg': '未找到要更新的订阅'})
            
        # 检查名称
        name = data.get('name', '').strip()
        if not name:
            return jsonify({'success': False, 'msg': '订阅名称不能为空'})
            
        # 检查名称是否与其他订阅重复（排除自身）
        existing_subscription = Rss.query.filter(
            Rss.name == name,
            Rss.id != subscription.id
        ).first()
        if existing_subscription:
            return jsonify({'success': False, 'msg': f'订阅名称 "{name}" 已存在'})
            
        # 处理enable值
        enable_value = data.get('enable', '0')
        enable = bool(int(enable_value)) if isinstance(enable_value, str) else bool(enable_value)
        
        # 处理encrypt值
        encrypt_value = data.get('encrypt', '0')
        encrypt = bool(int(encrypt_value)) if isinstance(encrypt_value, str) else bool(encrypt_value)
        url = data.get('url', '').strip() # 获取订阅地址
        # 处理加密URL
        if encrypt and '&androidid={androidid}' not in url:
            url = url.replace('&androidid={androidid}', '')
            url = url + '&androidid={androidid}'
        elif not encrypt and '&androidid={androidid}' in url:
            url = url.replace('&androidid={androidid}', '')
            url = url + '&androidid={androidid}'

        # 更新订阅信息
        subscription.name = name
        subscription.type = data.get('type', 'txt')
        subscription.url = url
        subscription.enable = enable
        subscription.encrypt = encrypt
        subscription.sort = data.get('sort', 0)
        subscription.remark = data.get('remark')
        subscription.update_time = datetime.now()
        
        # 保存更新
        db.session.commit()
        # 保存客户端配置
        client_config_save(rssname=name,rssurl=url)
        return jsonify({'success': True, 'msg': '更新成功'})
            
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(f"更新自定义订阅失败: {str(e)}")
        return jsonify({'success': False, 'msg': f'更新失败：{str(e)}'})
    
# 检查订阅地址是否有效
@iptvadmin_blueprint.post('/rss/rss_check')  
@authorize("system:iptvadmin:rss")
def rss_checks():

    """检查流媒体地址是否可访问"""
    try:
        data = request.get_json()
        if not data or 'url' not in data:
            return jsonify({'valid': False})
            
        url = data.get('url').strip()
        if not url:
            return jsonify({'valid': False})

        result = check_stream_url(url)
        return jsonify({'valid': result})

    except Exception as e:
        current_app.logger.error(f"检查地址失败: {url if 'url' in locals() else 'Unknown URL'}, 错误: {str(e)}")
        return jsonify({'valid': False})


import requests
import logging
import urllib3
from concurrent.futures import ThreadPoolExecutor, TimeoutError  # 直接导入 TimeoutError 以便更清晰

# 禁用 SSL 警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def ping_host(host, timeout=2):
    """
    使用ping检测主机是否可达
    
    Args:
        host (str): 主机地址
        timeout (int): 超时时间(秒)
    Returns:
        bool: 主机是否可达
    """
    import platform
    import subprocess
    
    # 根据操作系统选择ping命令参数
    param = '-n' if platform.system().lower() == 'windows' else '-c' # 参数
    timeout_param = '-w' if platform.system().lower() == 'windows' else '-W' # 超时参数
    
    command = ['ping', param, '1', timeout_param, str(timeout), host]
    
    try:
        # 执行ping命令，并抑制输出
        subprocess.run(
            command,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            timeout=timeout + 1  # 给命令执行增加1秒缓冲
        )
        return True
    except:
        return False

def check_stream_url(url, max_retries=2):
    """
    检查流媒体地址是否可访问
    
    Args:
        url (str): 要检查的URL
        max_retries (int): 最大重试次数
    Returns:
        bool: URL是否可访问
    """
    import requests
    import urllib3
    import time
    from urllib.parse import urlparse
    
    # 禁用SSL警告
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    
    # 处理URL格式
    try:
        if url.startswith('//'):
            url = 'http:' + url
        elif not url.startswith(('http://', 'https://')):
            url = 'http://' + url
            
        # 解析URL获取主机名
        parsed_url = urlparse(url)
        host = parsed_url.netloc.split(':')[0]  # 去除端口号
        
        # 先进行ping测试
        if not ping_host(host):
            return False
            
    except:
        return False
    
    # 设置请求头
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        'Accept': '*/*',
        'Connection': 'close'
    }
    
    retry_count = 0
    start_time = time.time()
    
    while retry_count < max_retries:
        try:
            # 检查是否超过总时间限制(15秒)
            if time.time() - start_time > 15:
                return False
            
            # 发送请求
            with requests.Session() as session:
                response = session.head(
                    url,
                    headers=headers,
                    timeout=5,
                    verify=False,
                    allow_redirects=True
                )
                return response.status_code in [200, 301, 302, 204]
                    
        except:
            retry_count += 1
            if retry_count < max_retries:
                time.sleep(1)
    
    return False

def aes_encrypt(data, sig="12315", appname="mytv", packagename="com.mytv", method="AES-128-ECB"):
    """
    使用OpenSSL风格的AES加密
    
    参数:
        data: 需要加密的字符串
        sig: 签名字符串
        appname: 应用名称
        packagename: 包名
        method: 加密方法(目前仅支持ECB模式)
    """
    try:
        # 生成密钥
        key = (sig + appname + packagename + 'AD80F93B542B' )
        key = hashlib.md5(key.encode()).hexdigest()
        key = hashlib.md5((key + appname + packagename).encode()).hexdigest()
        key = key[:16].encode('utf-8') 

        
        # 确保数据是字符串并转换为字节
        if not isinstance(data, str):
            data = str(data)
        data_bytes = data.encode('utf-8')
        
        # 计算填充
        block_size = 16
        pad_length = block_size - (len(data_bytes) % block_size)
        padding = bytes([pad_length] * pad_length)
        padded_data = data_bytes + padding
        
        # 创建cipher对象并加密
        cipher = Cipher(
            algorithms.AES(key),
            modes.ECB(),
            backend=default_backend()
        )
        encryptor = cipher.encryptor()
        encrypted = encryptor.update(padded_data) + encryptor.finalize()
        
        # Base64编码
        return base64.b64encode(encrypted).decode('utf-8')
        
    except Exception as e:
        current_app.logger.error(f"加密失败: {str(e)}")
        raise Exception(f"加密失败: {str(e)}")

def aes_decrypt(encrypted_data, sig="12315", appname="mytv", packagename="com.mytv",token="1234567890", method="AES-128-ECB"):
    """
    使用OpenSSL风格的AES解密
    
    参数:
        encrypted_data: base64编码的加密字符串
        sig: 签名字符串
        appname: 应用名称
        packagename: 包名
        method: 加密方法(目前仅支持ECB模式)
    """
    try:
        # 生成密钥
        key = (sig + appname + packagename + 'AD80F93B542B' )
        key = hashlib.md5(key.encode()).hexdigest()
        key = hashlib.md5((key + appname + packagename).encode()).hexdigest()
        key = key[:16].encode('utf-8') 
        
        # Base64解码
        encrypted_bytes = base64.b64decode(encrypted_data)
        
        # 创建cipher对象
        cipher = Cipher(
            algorithms.AES(key),
            modes.ECB(),
            backend=default_backend()
        )
        decryptor = cipher.decryptor()
        
        # 解密
        decrypted_padded = decryptor.update(encrypted_bytes) + decryptor.finalize()
        
        # 移除PKCS7填充
        pad_size = decrypted_padded[-1]
        decrypted = decrypted_padded[:-pad_size]
        
        return decrypted.decode('utf-8')
        
    except Exception as e:
        raise Exception(f"解密失败: {str(e)}")
    
# 客户端管理-主页
@iptvadmin_blueprint.route('/client/main')
@authorize("system:iptvadmin:main")
def client_main():
    """客户端管理页面"""
    try:
        # 初始化数据库表
        inspector = db.inspect(db.engine)
        if 'admin_iptv_client' not in inspector.get_table_names():
            Client.__table__.create(db.engine)
            current_app.logger.info("客户端设备表创建成功")

            # 查询数据库是否有数据并添加示例
            demo_client_exists = db.session.query(Client).count() > 0
            if not demo_client_exists:
                demo_client = Client(
                    androidId='99dfb46e741830eb',
                    deviceBrand='小米',
                    deviceName='小米盒子',
                    deviceOsVer='Android 10',
                    deviceMac='00:DB:25:1F:33:36',
                    sdkVer='28',
                    apkAppName='天光云影',
                    apkPackageName='com.chinablue.tv',
                    apkVer='3.3.7',
                    sign='3da4c6abdd46674cb017f89bc6bc8bdd',
                    config_file='default.json',
                    create_time=datetime.now()
                )
                db.session.add(demo_client)
                db.session.commit()

            # 读取配置文件
        current_dir = os.path.dirname(os.path.abspath(__file__))
        config_dir = os.path.join(current_dir, 'templates', 'client', 'config')
        json_files = [f for f in os.listdir(config_dir) if f.endswith('.json')]

        return render_template('client/main.html',json_files=json_files)

    except Exception as e:
        current_app.logger.error(f"访问客户端管理页面失败: {str(e)}")
        return render_template('client/main.html', error="初始化失败")
    finally:
        db.session.close()

# 客户端-授权
@iptvadmin_blueprint.post('/client/authorize')
@authorize("system:iptvadmin:client")
def client_authorize():
    """切换客户端授权状态"""
    try:
        id = request.form.get('id', type=int)
        authorize_status = request.form.get('authorize', type=int)
        
        client = Client.query.get(id)
        if not client:
            return fail_api(msg="客户端不存在")
            
        client.authorize = bool(authorize_status)
        db.session.commit()
        
        return success_api(msg="授权状态更新成功")
    except Exception as e:
        db.session.rollback()
        return fail_api(msg=f"授权状态更新失败: {str(e)}")

# 客户端-数据-查询
@iptvadmin_blueprint.get('/client/data')
@authorize("system:iptvadmin:client")
def client_data():
    """获取客户端数据"""
    try:
        # 获取分页参数
        page = request.args.get('page', 1, type=int)
        limit = request.args.get('limit', 10, type=int)
        
        # 构建查询
        query = Client.query
        
        # 搜索条件
        androidId = request.args.get('androidId')
        if androidId:
            query = query.filter(Client.androidId.like(f'%{androidId}%'))
            
        deviceName = request.args.get('deviceName')
        if deviceName:
            query = query.filter(Client.deviceName.like(f'%{deviceName}%'))
        
        # 获取总数
        total = query.count()
        
        # 分页查询
        clients = query.order_by(Client.id.desc())\
                      .offset((page - 1) * limit)\
                      .limit(limit)\
                      .all()
        
        # 读取配置文件
        current_dir = os.path.dirname(os.path.abspath(__file__))
        config_dir = os.path.join(current_dir, 'templates', 'client', 'config')
        json_files = [f for f in os.listdir(config_dir) if f.endswith('.json')]
        
        # 转换数据格式
        data = [{
            'id': client.id,
            'androidId': client.androidId,
            'deviceBrand': client.deviceBrand,
            'deviceName': client.deviceName,
            'deviceOsVer': client.deviceOsVer,
            'deviceMac': client.deviceMac,
            'sdkVer': client.sdkVer,
            'apkAppName': client.apkAppName,
            'apkPackageName': client.apkPackageName,
            'apkVer': client.apkVer,
            'sign': client.sign,
            'authorize': client.authorize,
            'configFile': client.config_file,
            'createTime': client.create_time.strftime('%Y-%m-%d %H:%M:%S') if client.create_time else None,
            'json_files': json_files  # 确保此处包含 json_files
        } for client in clients]
        
        # 返回符合layui表格要求的格式
        return {
            "code": 0,
            "msg": "",
            "count": total,
            "data": data
        }
        
    except Exception as e:
        current_app.logger.error(f"获取客户端数据失败: {str(e)}")
        return {
            "code": 1,
            "msg": "获取数据失败",
            "count": 0,
            "data": []
        }
    
# 查询客户端配置文件
@iptvadmin_blueprint.get('/client/config/data')
@authorize("system:iptvadmin:client")
def client_config_data():
    # 读取配置文件
        current_dir = os.path.dirname(os.path.abspath(__file__))
        config_dir = os.path.join(current_dir, 'templates', 'client', 'config')
        json_files = [f for f in os.listdir(config_dir) if f.endswith('.json')]
        
        return json_files
# 客户端-数据-更新配置
@iptvadmin_blueprint.post('/client/data/updateConfig')
@authorize("system:iptvadmin:client")
def client_data_updateConfig():
    """更新客户端配置"""
    try:
        client_id = request.form.get('id')
        config_file = request.form.get('configFile')
        client = Client.query.get(client_id)
        client.config_file = config_file
        db.session.commit()
        return success_api(msg="配置文件更新成功")
    except Exception as e:
        db.session.rollback()
        return fail_api(msg=f"配置文件更新失败: {str(e)}")  
# 客户端-数据-删除
@iptvadmin_blueprint.post('/client/data/remove')
@authorize("system:iptvadmin:client")
def client_data_remove():
    """删除客户端数据"""
    try:
        id = request.form.get('id')
        if not id:
            return fail_api(msg="参数错误")
            
        Client.query.filter_by(id=id).delete()
        db.session.commit()
        return success_api(msg="删除成功")
    except Exception as e:
        db.session.rollback()
        return fail_api(msg=f"删除失败: {str(e)}")

# 客户端-数据-批量删除
@iptvadmin_blueprint.post('/client/data/batchRemove')
@authorize("system:iptvadmin:client")
def client_data_remove_batch():
    """批量删除客户端数据"""
    try:
        ids = request.form.get('ids', '').split(',')
        if not ids:
            return fail_api(msg="请选择要删除的数据")
            
        Client.query.filter(Client.androidId.in_(ids)).delete(synchronize_session=False)
        db.session.commit()
        return success_api(msg="批量删除成功")
    except Exception as e:
        db.session.rollback()
        return fail_api(msg=f"批量删除失败: {str(e)}")




# 插入客户端日志记录
def insert_client_log(log_data=None):
    """插入客户端日志记录
    
    Args:
        log_data (dict): 日志数据字典,包含以下字段:
            - client_id: 客户端ID
            - client_version: 客户端版本 
            - client_ip: 客户端IP
            - client_model: 设备型号
            - client_system: 系统版本
            如果为None则使用默认值
            
    Returns:
        bool: 插入是否成功
        
    Examples:
        # 使用自定义数据插入
        log_data = {
            'client_id': '9876543210',
            'client_version': '2.0.0',
            'client_ip': '10.0.0.1',
            'client_model': '华为盒子',
            'client_system': 'Android 11'
        }
        success = insert_client_log(log_data)
        
        # 使用默认值插入
        success = insert_client_log()
    """
    try:
        # 默认值设置
        default_log = {
            'androidId': '1234567890',
            'deviceBrand': '小米盒子',
            'deviceName': '小米盒子',
            'deviceOsVer': 'Android 10',
            'deviceMac': '00:DB:25:1F:33:36',
            'sdkVer': '28',
            'apkAppName': '天光云影',
            'apkPackageName': 'com.chinablue.tv',
            'apkVer': '3.3.7',
            'sign': '3da4c6abdd46674cb017f89bc6bc8bdd'
        }
        
        # 如果传入数据为空,使用默认值
        if not log_data:
            log_data = default_log
        else:
            # 使用默认值补充缺失字段
            for key in default_log:
                if key not in log_data or not log_data[key]:
                    log_data[key] = default_log[key]
        
        # 初始化数据库表(如果不存在)
        inspector = db.inspect(db.engine)
        if 'admin_iptv_client_log' not in inspector.get_table_names():
            ClientLog.__table__.create(db.engine)
            current_app.logger.info("客户端日志表创建成功")
            
        # 创建日志记录
        client_log = ClientLog(
            client_id=log_data['client_id'],
            client_version=log_data['client_version'],
            client_ip=log_data['client_ip'],
            client_model=log_data['client_model'],
            client_system=log_data['client_system'],
            create_time=datetime.now()
        )
        
        # 插入数据库
        db.session.add(client_log)
        db.session.commit()
        
        current_app.logger.info(f"客户端日志插入成功: {log_data['client_id']}")
        return True
        
    except Exception as e:
        current_app.logger.error(f"插入客户端日志失败: {str(e)}")
        db.session.rollback()
        return False
    finally:
        db.session.close()

# 客户端上线日志
@iptvadmin_blueprint.route('/client/log')
@authorize("system:iptvadmin:client")
def client_log():
    """客户端上线日志"""
    return render_template('client/log.html')

# 客户端上线日志查询API
@iptvadmin_blueprint.get('/client/log/data')
@authorize("system:iptvadmin:client")
def client_log_data():
    """获取客户端上线日志数据"""
    # return jsonify({'code': 0, 'msg': 'success', 'count': 0, 'data': []})
    try:
        # 获取请求参数
        page = request.args.get('page', type=int, default=1)
        limit = request.args.get('limit', type=int, default=10)
        client_id = request.args.get('clientId', '')
        
        # 构建查询
        query = ClientLog.query
        if client_id:
            query = query.filter(ClientLog.client_id.like(f'%{xss_escape(client_id)}%'))
            
        # 统计总数
        total = query.count()
        
        # 分页查询
        logs = query.order_by(ClientLog.last_login.desc())\
                    .paginate(page=page, per_page=limit)
        
        # 构造返回数据
        data = [{
            'id': log.id,
            'clientId': log.client_id,
            'clientVersion': log.client_version,
            'clientIp': log.client_ip,
            'clientModel': log.client_model,
            'clientSystem': log.client_system,
            'lastLogin': str(log.last_login),
            'createTime': str(log.create_time)
        } for log in logs.items]
        
        return {
            'code': 0,
            'msg': 'success',
            'count': total,
            'data': data
        }
        
    except Exception as e:
        current_app.logger.error(f"获取客户端日志失败: {str(e)}")
        return {
            'code': 1,
            'msg': str(e),
            'count': 0,
            'data': []
        }
# 清除全部日志API
@iptvadmin_blueprint.post('/client/log/clear-all')
@authorize("system:iptvadmin:client")
def clear_all_client_log():
    """清除全部客户端日志"""
    try:
        # 删除所有日志记录
        result = ClientLog.query.delete()
        db.session.commit()
        
        return success_api(msg=f"成功清除全部日志，共{result}条")
    except Exception as e:
        db.session.rollback()
        return fail_api(msg=f"清除失败: {str(e)}")

# 清除日志API
@iptvadmin_blueprint.post('/client/log/clear')
@authorize("system:iptvadmin:client")
def clear_client_log():
    """清除客户端日志"""
    try:
        # 获取要清除的日期范围
        days = request.form.get('days', type=int, default=30)
        
        # 计算日期
        clear_date = datetime.now() - timedelta(days=days)
        
        # 删除指定日期之前的日志
        result = ClientLog.query.filter(ClientLog.create_time < clear_date).delete()
        db.session.commit()
        
        return success_api(msg=f"成功清除{result}条日志")
    except Exception as e:
        db.session.rollback()
        return fail_api(msg=f"清除失败: {str(e)}")
    
# 客户端服务配置
@iptvadmin_blueprint.route('/client/config', methods=['GET', 'POST'])
@authorize("system:iptvadmin:client")  # 添加权限验证装饰器
def edit_config():
    """编辑配置文件页面"""
    if request.method == 'POST':
        try:
            selected_file = request.form.get('json_file')
            json_content = request.form.get('json_content')

            if not selected_file:
                return fail_api(msg="请选择要编辑的文件")

            current_dir = os.path.dirname(os.path.abspath(__file__))
            config_dir = os.path.join(current_dir, 'templates', 'client', 'config')
            file_path = os.path.join(config_dir, selected_file)

            # 验证JSON格式
            try:
                json_data = json.loads(json_content)
                with open(file_path, 'w', encoding='utf-8') as f:
                    json.dump(json_data, f, ensure_ascii=False, indent=4)
                return success_api(msg="保存成功")
            except json.JSONDecodeError:
                return fail_api(msg="JSON格式错误，请检查内容")

        except Exception as e:
            current_app.logger.error(f"保存配置文件失败: {str(e)}")
            return fail_api(msg=f"保存失败: {str(e)}")

    # GET请求处理
    try:
        current_dir = os.path.dirname(os.path.abspath(__file__))
        config_dir = os.path.join(current_dir, 'templates', 'client', 'config')
        json_files = [f for f in os.listdir(config_dir) if f.endswith('.json')]
        return render_template('client/config.html', json_files=json_files)
    except Exception as e:
        current_app.logger.error(f"加载配置页面失败: {str(e)}")
        return fail_api(msg=f"加载页面失败: {str(e)}")

# 加载指定的 JSON 文件
@iptvadmin_blueprint.route('/client/config/<filename>', methods=['GET'])
@authorize("system:iptvadmin:client")  # 添加权限验证装饰器
def load_json_file(filename):
    """加载指定的 JSON 文件"""
    try:
        current_dir = os.path.dirname(os.path.abspath(__file__))
        config_dir = os.path.join(current_dir, 'templates', 'client', 'config')
        file_path = os.path.join(config_dir, filename)

        if not os.path.exists(file_path):
            return fail_api(msg="文件不存在")

        with open(file_path, 'r', encoding='utf-8') as f:
            json_data = f.read()

        # 将 json_data 的内容转换为字符串以便返回
        return success_api_data(msg="文件加载成功", data=json_data)  # 将数据转为字符串以适应msg参数
    except Exception as e:
        current_app.logger.error(f"加载JSON文件失败: {str(e)}")
        return fail_api(msg=f"加载失败: {str(e)}")
    
def success_api_data(msg: str = "成功", data: dict = None):
    """ 成功响应 默认值“成功” """
    response = {
        "success": True,
        "msg": msg,
    }
    if data is not None:
        response["data"] = data
    return jsonify(response)

# 保存客户端配置到config/config.json
# @iptvadmin_blueprint.post("/client/config/save")
# @authorize("system:iptvadmin:client")
def client_config_save(rssname='默认源',rssurl='http://127.0.0.1:20243/app/m3utotxt/index2.php?ch=huyapro'):
    """保存客户端配置"""
    try:
        import re
        import urllib.parse
        # 默认配置
        host = request.host # 获取当前主机
        # 需要对rssurl进行重新转义为url地址
        # rssurl = urllib.parse.quote(rssurl)
        
        default_config = {
            "code":200,
            "msg":"成功",
            "data":{
                "appAgreementAgreed": "true",
                "appStartupScreen": "Live",
                "uiUseClassicPanelScreen": "true",
                "iptvSourceCurrent": {
                    "name": rssname or '默认源',
                    "url": rssurl or f'http://{host}/app/m3utotxt/index2.php?ch=huyapro'
                    },
                "updateForceRemind": "true",
                "updateChannel": "stable",
                "updateUrl": f"http://{host}/app/tv-standard.json"
            }
        }

        # 保存配置
        # 判断是否存在当前目录下的templates/client/config/default.json
        # 获取当前文件所在目录
        current_dir = os.path.dirname(os.path.abspath(__file__))
        config_path_default = current_dir + f'/templates/client/config/default.json'
        if not os.path.exists(config_path_default):
            default_config = {
                "code":200,
                "msg":"成功",
                "data":{
                    "appAgreementAgreed": "true",
                    "appStartupScreen": "Live",
                    "uiUseClassicPanelScreen": "true",
                    "iptvSourceCurrent": {
                            "name": str(rssname) or str('默认源'),
                            "url": str(rssurl) or str(f'http://{host}/app/m3utotxt/index2.php?ch=huyapro')
                        },
                    "updateForceRemind": "true",
                    "updateChannel": "stable",
                    "updateUrl": f"http://{host}/app/tv-standard.json"
                }
            }
            with open(config_path_default, 'w', encoding='utf-8') as f:  # 创建文件或者覆盖
                json.dump(default_config, f, ensure_ascii=False, indent=4) # 格式化json数据
                # json.dump(default_config, f, indent=4) # 格式化json数据


        # 构建配置文件路径
        config_path = current_dir + f'/templates/client/config/{rssname}.json'

        if not os.path.exists(config_path):
            with open(config_path, 'w', encoding='utf-8') as f:  # 创建文件或者覆盖
                json.dump(default_config, f, ensure_ascii=False, indent=4) # 格式化json数据
        else:
            with open(config_path, 'w', encoding='utf-8') as f:  # 创建文件或者覆盖
                json.dump(default_config, f, ensure_ascii=False, indent=4) # 格式化json数据 
    except Exception as e:
        pass

# 删除客户端配置
# @iptvadmin_blueprint.post('/client/config/delete')
# @authorize("system:iptvadmin:client")
def delete_client_config(rssname=None):
    """删除客户端配置"""
    try:
        if rssname:
            # 获取当前文件所在目录
            current_dir = os.path.dirname(os.path.abspath(__file__))
            # 构建配置文件路径
            config_path = current_dir + f'/templates/client/config/{rssname}.json'
            # 删除配置文件
        os.remove(config_path)
        return success_api(msg=f"成功删除{rssname}配置")
    except Exception as e:
        # pass
        return fail_api(msg=f"删除失败: {str(e)}")

# 客户端-数据-更新配置api
@iptvadmin_blueprint.route('/client/data/config',methods=['GET','POST'])
# @authorize("system:iptvadmin:client")
def client_data_config():
    '''
    {
    "deviceBrand":"OnePlus",
    "deviceName":"HD1910",
    "deviceOsVer":"9",
    "deviceMac":"00:DB:25:1F:33:36",
    "sdkVer":28,
    "androidId":"99dfb46e741830eb",
    "apkAppName":"天光云影",
    "apkPackageName":"com.chinablue.tv",
    "apkVer":"3.3.7","t":1736179119,
    "sign":"3da4c6abdd46674cb017f89bc6bc8bdd"
    }
    '''     
    try:
        # 获取json数据
        post_data = request.get_json()
        androidId = post_data.get('androidId') or '非法异常'  # 获取客户端ID
        APPversion = post_data.get('apkVer') or "未知" # 获取客户端版本
        client_model = post_data.get('deviceBrand') or "未知" # 获取客户端品牌
        client_name = post_data.get('deviceName') or "未知" # 获取客户端型号
        client_system = post_data.get('deviceOsVer') or "未知" # 获取客户端系统
        deviceMac = post_data.get('deviceMac') or "未知" # 获取客户端MAC
        apkAppName = post_data.get('apkAppName') or "未知" # 获取客户端名称
        apkPackageName = post_data.get('apkPackageName') or "未知" # 获取客户端包名
        apkVer = post_data.get('apkVer') or "未知" # 获取客户端版本
        sdkVer = post_data.get('sdkVer') or "未知" # 获取客户端SDK版本
        t = post_data .get('t') or "未知" # 获取客户端时间
        sign = post_data .get('sign') or "未知" # 获取客户端签名

        print("客户端ID：", androidId)
        print("客户端MAC：", deviceMac)
        print("客户端名称：", apkAppName)
        print("客户端包名：", apkPackageName)
        print("客户端签名：", sign)
        if androidId:
            log_data = {
            'client_id': androidId,  # 客户端ID
            'client_version': APPversion or "未知",  # 客户端版本
            'client_ip': request.remote_addr or "未知",  # 客户端IP
            'client_model': client_model or "未知",  # 客户端型号
            'client_system': client_system or "未知",  # 客户端系统
            'create_time': datetime.now()  # 创建时间
            }
            # 将客户端请求参数插入到客户端日志表中
            try:
                insert_client_log(log_data)
            except Exception as e:
                current_app.logger.error(f"插入客户端日志失败: {str(e)}")
                pass
        
    
            # 客户端配置文件目录
            current_dir = os.path.dirname(os.path.abspath(__file__))
            config_dir = os.path.join(current_dir, 'templates', 'client', 'config')
            default_file = os.path.join(config_dir, f'default.json')
            # 查询客户端数据androidid是否存在
            client = Client.query.filter_by(androidId=androidId).first()
            if not client: # 客户端数据不存在，则新增新客户端信息，默认配置文件
                # 新增新客户端信息
                # id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='主键ID')
                # androidId = db.Column(db.String(100), nullable=True, comment='安卓ID')
                # deviceBrand = db.Column(db.String(100), nullable=True, comment='设备品牌')
                # deviceName = db.Column(db.String(100), nullable=True, comment='设备名称')
                # deviceOsVer = db.Column(db.String(100), nullable=True, comment='设备系统版本')
                # deviceMac = db.Column(db.String(100), nullable=True, comment='设备MAC')
                # sdkVer = db.Column(db.String(100), nullable=True, comment='SDK版本')
                # apkAppName = db.Column(db.String(100), nullable=True, comment='APP名称')
                # apkPackageName = db.Column(db.String(100), nullable=True, comment='APP包名')
                # apkVer = db.Column(db.String(100), nullable=True, comment='APP版本')
                # sign = db.Column(db.String(100), nullable=True, comment='签名')
                # authorize = db.Column(db.Boolean, default=False, comment='授权状态')
                # config_file = db.Column(db.String(100), nullable=True, default='default.json', comment='配置文件') 
                # create_time = db.Column(db.DateTime, default=datetime.now, comment='创建时间')
                # update_time = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now, comment='更新时间')
                print('客户端不存在,生成新客户端配置')
                new_client = Client(
                    androidId=androidId,
                    deviceBrand=client_model,
                    deviceName=client_name,
                    deviceOsVer=client_system,
                    deviceMac=deviceMac,
                    sdkVer=sdkVer,
                    apkAppName=apkAppName,
                    apkPackageName=apkPackageName,
                    apkVer=apkVer,
                    sign=sign,
                    authorize=False,
                    config_file='default.json'
                )
                # print(new_client)  
                try:
                    db.session.add(new_client)
                    db.session.commit()
                except Exception as e:
                    current_app.logger.error(f"插入客户端数据失败: {str(e)}")
                    return jsonify({'code': 400, 'error': f'警告，插入客户端数据失败'})
                
                db.session.close()
                return jsonify({'code': 200, 'msg': f'请授权客户端'})
            else:
                print('客户端已存在,读取配置文件')
                client_config = client.config_file
                # 客户端配置文件
                config_file = os.path.join(config_dir, f'{client_config}')
                print('文件地址:',config_file)
                # 如果客户端配置文件不存在，则使用默认配置
                if not os.path.exists(config_file):
                    with open(default_file , 'r', encoding='utf-8') as f:
                        config_data = json.load(f)
                    print(config_data)
                    return config_data
                else:
                    # 读取客户端配置
                    with open(config_file, 'r', encoding='utf-8') as f:
                        config_data = json.load(f)
                    # 返回数据json
                    print(config_data)
                    return config_data    
        else:
            print('客户端不存在')
            return jsonify({'code': 400, 'error': f'警告，非法异常访问'})
        
    except Exception as e:
        print(f'警告，非法异常访问{e}')
        return jsonify({'code': 400, 'error': f'警告，非法异常访问'})


